﻿using System;
using System.Linq;
using System.Text;
using EaseDapper.Abstract;
using EaseDapper.Interface;
using EaseDapper.Constants;
using System.Linq.Expressions;
using System.ComponentModel.DataAnnotations.Schema;
using EaseDapper.Providers.ExpressionContentProvider;

namespace EaseDapper
{
    public class MySqlUpdateExpressions<T> : IUpdateExpressions<T> where T : class
    {
        private static readonly object obj_content_lock = new object();
        protected static string TableName { get; set; }
        protected static StringBuilder SqlSetString { get; set; }
        protected static StringBuilder SqlWhereString { get; set; }
        private ContentProvider _content;
        public ContentProvider Content
        {
            get
            {
                if (_content is null)
                {
                    lock (obj_content_lock)
                    {
                        _content = new ContentProvider();
                    }
                }
                return _content;
            }
        }

        public MySqlUpdateExpressions()
        {
            string tableName = typeof(T).Name;
            dynamic tableattr = typeof(T).GetCustomAttributes(true).SingleOrDefault(attr => attr.GetType().Name == typeof(TableAttribute).Name) as dynamic;
            if (tableattr != null)
            {
                tableName = tableattr.Name;
            }
            TableName = tableName;
            SqlSetString = new StringBuilder();
            SqlWhereString = new StringBuilder();
        }

        public Func<Expression<Func<T, bool>>, Func<Expression<Func<T, bool>>, int>> Invoke => Update.Currey();

        private Func<Expression<Func<T, bool>>, Expression<Func<T, bool>>, int> Update => (SetValue, WhereValue) =>
        {
            return SetValues(SetValue).Where(WhereValue).Execute();
        };

        public IUpdateExpressions<T> SetValues(Expression<Func<T, bool>> expression)
        {
            AppendSetString(Content.Builder(expression.Body, QueryType.SET));
            return this;
        }

        public IUpdateExpressions<T> Where(Expression<Func<T, bool>> expression)
        {
            AppendWhereString(Content.Builder(expression.Body, QueryType.WHERE));
            return this;
        }

        public int Execute()
        {
            lock (SqlWhereString)
            {
                return DapperExecute.Instance.Execute(this.ToString());
            }
        }

        private void AppendSetString(object value)
        {
            SqlSetString.Append(value);
        }

        private void AppendWhereString(object value)
        {
            if (SqlWhereString is null)
            {
                SqlWhereString = new StringBuilder();
            }
            if (SqlWhereString.Length.Equals(0))
            {
                SqlWhereString.Append(" WHERE ");
            }
            else if (SqlWhereString.Length > 0)
            {
                SqlWhereString.Append(" AND ");
            }
            SqlWhereString.Append(value);
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(string.Format(Templates.UpdateString, TableName ?? typeof(T).Name));
            if (SqlSetString != null && SqlSetString.Length > 0)
            {
                sb.Append(SqlSetString);
            }
            if (SqlWhereString != null && SqlWhereString.Length > 0)
            {
                sb.Append(SqlWhereString);
            }
            return sb.ToString();
        }
    }
}
